/***
 * Copyright (c) 2021-2031 murenchao
 * fig is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *       http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package cool.taomu.software.fig.core

import cool.taomu.software.fig.asm.generate.GenerateUtils
import cool.taomu.software.fig.classloader.FigClassLoaderManage
import cool.taomu.software.fig.core.MqttCallSite
import cool.taomu.software.fig.mqtt.client.paho.CallbackTemplate
import cool.taomu.software.fig.mqtt.client.paho.MQTTSubscriber
import cool.taomu.software.fig.mqtt.client.paho.annotation.MqttClient
import cool.taomu.software.fig.mqtt.client.paho.annotation.Subscriber
import java.util.List
import java.util.UUID
import java.util.Vector
import org.eclipse.paho.client.mqttv3.MqttCallback
import org.objectweb.asm.Opcodes
import org.objectweb.asm.commons.GeneratorAdapter
import org.objectweb.asm.commons.Method
import cool.taomu.software.fig.configure.ConfigureManage

class CreateMqttClient {
    val fig = new FigClassLoaderManage();
    val config = ConfigureManage.loadConfig();
    val static CLASS_NAME_PREFIX = "FigCallback_";
    val static DYNAMIC_CALL = "void call(java/lang/String,java/lang/String,java/lang/String,org/eclipse/paho/client/mqttv3/MqttMessage)";
    def create(Class<?> ... zlasses) {
        val List<MQTTSubscriber> subscribers = new Vector<MQTTSubscriber>();
        zlasses.filterNull.forEach [ zlass |
            val mqttClient = zlass.getAnnotation(MqttClient);
            if (mqttClient !== null) {
                zlass.declaredMethods.forEach [ method |
                    var sub = method.getAnnotation(Subscriber)
                    if (sub !== null) {
                        var g = new GenerateUtils();
                        var uuidClass = CLASS_NAME_PREFIX + UUID.randomUUID.toString.replace("-", "");
                        var zlassBytes = g.gen(uuidClass, CallbackTemplate, null, [ classVisitor, superZlass, inter |
                            MqttCallback.declaredMethods.forEach [ m |
                                if (m.name.equals("messageArrived")) {
                                    val ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC, Method.getMethod(m), null, null,
                                        classVisitor);
                                    ga.push(zlass.name);
                                    ga.push(method.name);
                                    ga.loadArg(0);
                                    ga.loadArg(1);
                                    var destMethod = Method.getMethod(DYNAMIC_CALL,true);
                                    GenerateUtils.invokeDynamic(ga, MqttCallSite, destMethod);
                                    ga.returnValue();
                                    ga.endMethod();
                                }
                            ]
                        ]);
                        fig.register(uuidClass, zlassBytes);
                        var a = new MQTTSubscriber(
                            config.mqtt.username.trim,
                            config.mqtt.password.trim,
                            mqttClient.timeout,
                            mqttClient.keepAlive,
                            sub.clientId.trim.equals("uuid") ? UUID.randomUUID.toString() : sub.clientId.trim,
                            config.mqtt.ip,
                            config.mqtt.port,
                            sub.qos,
                            sub.topic,
                            mqttClient.cleanSession,
                            fig.getBean(uuidClass) as CallbackTemplate
                        )
                        subscribers.add(a);
                    }
                ]
            }
        ]
        return subscribers;
    }
}
